package multithreading;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ClassName: DiningPhilosophers
 * @Description TODO
 * @Author skywingking
 * @Date 2021/11/20 11:47 下午
 **/
public class DiningPhilosophers {
    private AtomicInteger fork = new AtomicInteger(0);
    private final int[] forkMask = new int[]{1,2,4,8,16};

    public DiningPhilosophers() {

    }

    // call the run() method of any runnable to execute its code
    public void wantsToEat(int philosopher,
                           Runnable pickLeftFork,
                           Runnable pickRightFork,
                           Runnable eat,
                           Runnable putLeftFork,
                           Runnable putRightFork) throws InterruptedException {
        int leftMask = forkMask[(philosopher + 1) % 5], rightMask = forkMask[philosopher];

        //编号为偶数的哲学家，优先拿起左边的叉子，再拿起右边的叉子
        if (philosopher % 2 == 0) {
            while (!pickFork(leftMask)) {Thread.sleep(1); }    //拿起左边的叉子
            while (!pickFork(rightMask)) {Thread.sleep(1);}   //拿起右边的叉子
        }//编号为奇数的哲学家，优先拿起右边的叉子，再拿起左边的叉子
        else {
            while (!pickFork(rightMask)){ Thread.sleep(1);  }  //拿起右边的叉子
            while (!pickFork(leftMask)) {Thread.sleep(1);  }   //拿起左边的叉子
        }

        pickLeftFork.run();    //拿起左边的叉子 的具体执行
        pickRightFork.run();    //拿起右边的叉子 的具体执行

        eat.run();    //吃意大利面 的具体执行

        putLeftFork.run();    //放下左边的叉子 的具体执行
        putRightFork.run();    //放下右边的叉子 的具体执行

        while (!putFork(rightMask)){ Thread.sleep(1);}    //放下右边的叉子
        while (!putFork(leftMask)){ Thread.sleep(1); }    //放下左边的叉子

    }

    private boolean pickFork(int mask) {
        int expect = fork.get();
        return (expect & mask) > 0 ? false : fork.compareAndSet(expect, expect ^ mask);
    }

    private boolean putFork(int mask) {
        int expect = fork.get();
        return fork.compareAndSet(expect, expect ^ mask);
    }
}